using LibGit2Sharp;
using Microsoft.Extensions.Logging;
using SumerCoreDevOps.Infrastructure.Configuration;

namespace SumerCoreDevOps.Infrastructure.Libraries;

/// <summary>
/// Git 操作库
/// </summary>
public class GitLibrary
{
    private readonly ILogger<GitLibrary> _logger;
    private readonly SystemConfigManager? _configManager;

    /// <summary>
    /// 日志事件（消息，级别）
    /// </summary>
    public event Action<string, string>? OnLog;

    public GitLibrary(ILogger<GitLibrary> logger, SystemConfigManager? configManager = null)
    {
        _logger = logger;
        _configManager = configManager;
    }

    /// <summary>
    /// 记录日志并触发事件
    /// </summary>
    private void Log(string message, string level = "Info")
    {
        switch (level)
        {
            case "Info":
                _logger.LogInformation(message);
                break;
            case "Warning":
                _logger.LogWarning(message);
                break;
            case "Error":
                _logger.LogError(message);
                break;
            default:
                _logger.LogDebug(message);
                break;
        }

        OnLog?.Invoke(message, level);
    }

    /// <summary>
    /// 获取 Git 签名信息（优先级：环境变量 > 配置管理系统 > 默认值）
    /// </summary>
    private Signature GetGitSignature()
    {
        // 1. 优先从环境变量读取（容器化部署场景）
        var gitUserName = Environment.GetEnvironmentVariable("GIT_USER_NAME");
        var gitUserEmail = Environment.GetEnvironmentVariable("GIT_USER_EMAIL");

        // 2. 如果环境变量未设置，从配置管理系统读取
        if ((string.IsNullOrEmpty(gitUserName) || string.IsNullOrEmpty(gitUserEmail)) && _configManager != null)
        {
            try
            {
                gitUserName ??= _configManager.GetConfigValueAsync("Git.UserName").GetAwaiter().GetResult();
                gitUserEmail ??= _configManager.GetConfigValueAsync("Git.UserEmail").GetAwaiter().GetResult();
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "从配置管理系统读取 Git 用户信息失败，将使用默认值");
            }
        }

        // 3. 使用默认值
        gitUserName ??= "SumerDevOps";
        gitUserEmail ??= "devops@sumer.com";

        _logger.LogDebug("使用 Git 签名: {UserName} <{UserEmail}>", gitUserName, gitUserEmail);

        return new Signature(
            new LibGit2Sharp.Identity(gitUserName, gitUserEmail),
            DateTimeOffset.Now);
    }

    /// <summary>
    /// 克隆仓库
    /// </summary>
    public async Task<bool> CloneRepositoryAsync(
        string repositoryUrl,
        string localPath,
        string? branch = null,
        string? username = null,
        string? password = null)
    {
        try
        {
            Log($"开始克隆仓库: {repositoryUrl} -> {localPath}");

            var options = new CloneOptions
            {
                BranchName = branch
            };

            if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password))
            {
                options.FetchOptions.CredentialsProvider = (url, usernameFromUrl, types) =>
                    new UsernamePasswordCredentials
                    {
                        Username = username,
                        Password = password
                    };
            }

            await Task.Run(() => Repository.Clone(repositoryUrl, localPath, options));

            Log($"克隆仓库成功: {localPath}");
            return true;
        }
        catch (Exception ex)
        {
            Log($"克隆仓库失败: {repositoryUrl} - {ex.Message}", "Error");
            return false;
        }
    }

    /// <summary>
    /// 拉取最新代码
    /// </summary>
    public async Task<bool> PullAsync(
        string repositoryPath,
        string? username = null,
        string? password = null)
    {
        try
        {
            _logger.LogInformation("开始拉取代码: {Path}", repositoryPath);

            await Task.Run(() =>
            {
                using var repo = new Repository(repositoryPath);

                var options = new PullOptions();

                if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password))
                {
                    options.FetchOptions = new FetchOptions
                    {
                        CredentialsProvider = (url, usernameFromUrl, types) =>
                            new UsernamePasswordCredentials
                            {
                                Username = username,
                                Password = password
                            }
                    };
                }

                var signature = GetGitSignature();

                Commands.Pull(repo, signature, options);
            });

            _logger.LogInformation("拉取代码成功: {Path}", repositoryPath);
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "拉取代码失败: {Path}", repositoryPath);
            return false;
        }
    }

    /// <summary>
    /// 切换分支
    /// </summary>
    public async Task<bool> CheckoutBranchAsync(string repositoryPath, string branchName)
    {
        try
        {
            _logger.LogInformation("切换分支: {Branch} in {Path}", branchName, repositoryPath);

            await Task.Run(() =>
            {
                using var repo = new Repository(repositoryPath);
                var branch = repo.Branches[branchName];

                if (branch == null)
                {
                    throw new InvalidOperationException($"分支 '{branchName}' 不存在");
                }

                Commands.Checkout(repo, branch);
            });

            _logger.LogInformation("切换分支成功: {Branch}", branchName);
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "切换分支失败: {Branch}", branchName);
            return false;
        }
    }

    /// <summary>
    /// 获取最新提交信息
    /// </summary>
    public async Task<CommitInfo?> GetLatestCommitAsync(string repositoryPath)
    {
        try
        {
            return await Task.Run(() =>
            {
                using var repo = new Repository(repositoryPath);
                var commit = repo.Head.Tip;

                if (commit == null) return null;

                return new CommitInfo
                {
                    Hash = commit.Sha,
                    Message = commit.Message,
                    Author = commit.Author.Name,
                    Email = commit.Author.Email,
                    Timestamp = commit.Author.When.DateTime
                };
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取提交信息失败: {Path}", repositoryPath);
            return null;
        }
    }

    /// <summary>
    /// 获取标签列表
    /// </summary>
    public async Task<List<string>> GetTagsAsync(string repositoryPath)
    {
        try
        {
            return await Task.Run(() =>
            {
                using var repo = new Repository(repositoryPath);
                return repo.Tags.Select(t => t.FriendlyName).ToList();
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取标签列表失败: {Path}", repositoryPath);
            return [];
        }
    }

    /// <summary>
    /// 获取匹配模式的标签（支持通配符）
    /// </summary>
    /// <param name="repositoryPath">仓库路径</param>
    /// <param name="pattern">标签模式，如 v*.*.* 或 release-*</param>
    /// <param name="latestOnly">是否只返回最新的标签</param>
    public async Task<List<string>> GetTagsMatchingPatternAsync(
        string repositoryPath,
        string pattern,
        bool latestOnly = false)
    {
        try
        {
            Log($"搜索匹配模式的标签: {pattern}");

            return await Task.Run(() =>
            {
                using var repo = new Repository(repositoryPath);

                // 将通配符模式转换为正则表达式
                var regexPattern = "^" + System.Text.RegularExpressions.Regex.Escape(pattern)
                    .Replace("\\*", ".*")
                    .Replace("\\?", ".") + "$";

                var regex = new System.Text.RegularExpressions.Regex(regexPattern);

                var matchingTags = repo.Tags
                    .Where(t => regex.IsMatch(t.FriendlyName))
                    .OrderByDescending(t => t.Target is Commit commit ? commit.Author.When : DateTimeOffset.MinValue)
                    .Select(t => t.FriendlyName)
                    .ToList();

                Log($"找到 {matchingTags.Count} 个匹配的标签");

                if (latestOnly && matchingTags.Any())
                {
                    var latest = matchingTags.First();
                    Log($"选择最新标签: {latest}");
                    return new List<string> { latest };
                }

                return matchingTags;
            });
        }
        catch (Exception ex)
        {
            Log($"获取匹配标签失败: {ex.Message}", "Error");
            return [];
        }
    }

    /// <summary>
    /// checkout 到指定标签
    /// </summary>
    public async Task<bool> CheckoutTagAsync(string repositoryPath, string tagName)
    {
        try
        {
            Log($"切换到标签: {tagName}");

            await Task.Run(() =>
            {
                using var repo = new Repository(repositoryPath);
                var tag = repo.Tags[tagName];

                if (tag == null)
                {
                    throw new InvalidOperationException($"标签 '{tagName}' 不存在");
                }

                // 获取 tag 指向的 commit
                var commit = tag.Target is Commit c ? c : tag.PeeledTarget as Commit;
                if (commit == null)
                {
                    throw new InvalidOperationException($"无法从标签 '{tagName}' 获取 commit");
                }

                // Checkout 到 commit (detached HEAD 状态)
                Commands.Checkout(repo, commit);
            });

            Log($"切换标签成功: {tagName}");
            return true;
        }
        catch (Exception ex)
        {
            Log($"切换标签失败: {tagName} - {ex.Message}", "Error");
            return false;
        }
    }

    /// <summary>
    /// 从标签创建并切换到新分支
    /// </summary>
    public async Task<bool> CreateBranchFromTagAsync(
        string repositoryPath,
        string tagName,
        string branchName)
    {
        try
        {
            Log($"从标签 '{tagName}' 创建分支: {branchName}");

            await Task.Run(() =>
            {
                using var repo = new Repository(repositoryPath);
                var tag = repo.Tags[tagName];

                if (tag == null)
                {
                    throw new InvalidOperationException($"标签 '{tagName}' 不存在");
                }

                // 获取 tag 指向的 commit
                var commit = tag.Target is Commit c ? c : tag.PeeledTarget as Commit;
                if (commit == null)
                {
                    throw new InvalidOperationException($"无法从标签 '{tagName}' 获取 commit");
                }

                // 检查分支是否已存在
                var existingBranch = repo.Branches[branchName];
                if (existingBranch != null)
                {
                    Log($"分支 '{branchName}' 已存在，直接切换", "Warning");
                    Commands.Checkout(repo, existingBranch);
                }
                else
                {
                    // 创建新分支
                    var newBranch = repo.CreateBranch(branchName, commit);
                    Commands.Checkout(repo, newBranch);
                    Log($"分支 '{branchName}' 创建成功");
                }
            });

            Log($"从标签创建分支成功: {branchName}");
            return true;
        }
        catch (Exception ex)
        {
            Log($"从标签创建分支失败: {ex.Message}", "Error");
            return false;
        }
    }

    /// <summary>
    /// 克隆仓库并checkout到指定标签或基于标签创建分支
    /// </summary>
    public async Task<(bool Success, string? TagName, string? BranchName)> CloneWithTagAsync(
        string repositoryUrl,
        string localPath,
        string? tagPattern = null,
        bool createBranchFromTag = false,
        string? branchNameTemplate = null,
        string? username = null,
        string? password = null)
    {
        try
        {
            Log($"开始克隆仓库（Tag模式）: {repositoryUrl} -> {localPath}");

            // 1. 先克隆整个仓库（不指定分支）
            var options = new CloneOptions();

            if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password))
            {
                options.FetchOptions.CredentialsProvider = (url, usernameFromUrl, types) =>
                    new UsernamePasswordCredentials
                    {
                        Username = username,
                        Password = password
                    };
            }

            await Task.Run(() => Repository.Clone(repositoryUrl, localPath, options));
            Log($"克隆仓库成功");

            // 2. 如果指定了 tag 模式，查找匹配的 tag
            if (!string.IsNullOrEmpty(tagPattern))
            {
                var matchingTags = await GetTagsMatchingPatternAsync(localPath, tagPattern, latestOnly: true);

                if (matchingTags.Count == 0)
                {
                    Log($"未找到匹配模式的标签: {tagPattern}", "Warning");
                    return (true, null, null);
                }

                var selectedTag = matchingTags.First();
                Log($"选择标签: {selectedTag}");

                // 3. 决定是创建分支还是直接 checkout tag
                if (createBranchFromTag)
                {
                    // 生成分支名称
                    var branchName = string.IsNullOrEmpty(branchNameTemplate)
                        ? $"branch-from-{selectedTag}"
                        : branchNameTemplate.Replace("{tag}", selectedTag);

                    var branchSuccess = await CreateBranchFromTagAsync(localPath, selectedTag, branchName);
                    return (branchSuccess, selectedTag, branchName);
                }
                else
                {
                    // 直接 checkout tag
                    var checkoutSuccess = await CheckoutTagAsync(localPath, selectedTag);
                    return (checkoutSuccess, selectedTag, null);
                }
            }

            return (true, null, null);
        }
        catch (Exception ex)
        {
            Log($"克隆仓库（Tag模式）失败: {repositoryUrl} - {ex.Message}", "Error");
            return (false, null, null);
        }
    }
}

/// <summary>
/// 提交信息
/// </summary>
public class CommitInfo
{
    public string Hash { get; set; } = null!;
    public string Message { get; set; } = null!;
    public string Author { get; set; } = null!;
    public string Email { get; set; } = null!;
    public DateTime Timestamp { get; set; }
}
